﻿#include "RespawnTimer.h"

namespace Server::MirEnvir
{

    RespawnSave::RespawnSave()
    {
    }

    RespawnSave::RespawnSave(BinaryReader *reader)
    {
        Spawned = reader->ReadBoolean();
        NextSpawnTick = reader->ReadUInt64();
        RespawnIndex = reader->ReadInt32();
    }

    void RespawnSave::Save(BinaryWriter *writer)
    {
        writer->Write(Spawned);
        writer->Write(NextSpawnTick);
        writer->Write(RespawnIndex);
    }

    RespawnTickOption::RespawnTickOption()
    {
    }

    RespawnTickOption::RespawnTickOption(BinaryReader *reader)
    {
        UserCount = reader->ReadInt32();
        DelayLoss = reader->ReadDouble();
    }

    void RespawnTickOption::Save(BinaryWriter *writer)
    {
        writer->Write(UserCount);
        writer->Write(DelayLoss);
    }

    std::string RespawnTickOption::ToString()
    {
        return StringHelper::formatSimple("+{0} users", UserCount);
    }

    Server::MirEnvir::Envir *RespawnTimer::getEnvir()
    {
        return Envir::getMain();
    }

    RespawnTimer::RespawnTimer()
    {
        RespawnTickOption *Option = new RespawnTickOption();
        Option->UserCount = 0;
        Option->DelayLoss = 1.0;
        Respawn.push_back(Option);
        //LastTick = Envir.Time;

//C# TO C++ CONVERTER TODO TASK: A 'delete Option' statement was not added since Option was passed to a method or constructor. Handle memory management manually.
    }

    RespawnTimer::RespawnTimer(BinaryReader *reader)
    {
        BaseSpawnRate = reader->ReadByte();
        CurrentTickcounter = reader->ReadUInt64();
        LastTick = getEnvir()->getTime();
        Respawn.clear();
        int Optioncount = reader->ReadInt32();
        for (int i = 0; i < Optioncount; i++)
        {
            RespawnTickOption *Option = new RespawnTickOption(reader);
            Respawn.push_back(Option);

//C# TO C++ CONVERTER TODO TASK: A 'delete Option' statement was not added since Option was passed to a method or constructor. Handle memory management manually.
        }
        CurrentDelay = static_cast<long long>(BankersRounding::round(static_cast<double>(BaseSpawnRate) * static_cast<double>(60000)));
    }

    void RespawnTimer::Save(BinaryWriter *writer)
    {
        writer->Write(BaseSpawnRate);
        writer->Write(CurrentTickcounter);
        writer->Write(Respawn.size());
        for (auto Option : Respawn)
        {
            Option->Save(writer);
        }
    }

    void RespawnTimer::Process()
    {
        //by always rechecking tickspeed we reduce the chance of having respawns get silly on situations where usercount goes up or down fast (like say after a server reboot)
        GetTickSpeed();

        if (getEnvir()->getTime() >= (LastTick + CurrentDelay))
        {
            CurrentTickcounter++;
            if (CurrentTickcounter == std::numeric_limits<long long>::max()) //by using long instead of ulong here you basicaly have a huge safe zone on the respawn ticks of mobs
            {
                CurrentTickcounter = 0;
            }
            LastTick = getEnvir()->getTime();
        }
    }

    void RespawnTimer::GetTickSpeed()
    {
        if (LastUsercount == getEnvir()->getPlayerCount())
        {
            return;
        }
        LastUsercount = getEnvir()->getPlayerCount();
        double bonus = 1.0;
        for (auto Option : Respawn)
        {
            if (Option->UserCount <= LastUsercount)
            {
                bonus = std::min(bonus, Option->DelayLoss);
            }
        }
        CurrentDelay = static_cast<long long>(BankersRounding::round((BaseSpawnRate * 60000) * bonus));
    }
}
